package com.umpay.utils;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;

/**
 * map 转xml
 * @ClassName: MapMutualXmlUtil  
 * @Description: TODO(这里用一句话描述这个类的作用)  
 * @author hp  
 * @date 2018年1月23日
 */

public class MapMutualXmlUtil {

	/**
	 * map转xml报文
	 * 
	 * @param map
	 *            需要转换的数据
	 * @param encoding
	 *            转换数据的字符集
	 * @param root
	 *            根节点
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public static String callMapToXML(Map map, String encoding, String root) {
		StringBuffer sb = new StringBuffer();
		sb.append("<?xml version=\"1.0\" encoding=\"" + encoding + "\"?><" + root + ">");
		mapToXMLTest2(map, sb);
		sb.append("</" + root + ">");
		//System.out.println(sb.toString());
		return sb.toString();
	}

	/**
	 * map拼接xml字符串
	 * 
	 * @param map
	 * @param sb
	 */
	@SuppressWarnings("rawtypes")
	private static void mapToXMLTest2(Map map, StringBuffer sb) {
		Set set = map.keySet();
		for (Iterator it = set.iterator(); it.hasNext();) {
			String key = (String) it.next();
			Object value = map.get(key);
			if (null == value)
				value = "";
			if (value.getClass().getName().equals("java.util.ArrayList")) {
				ArrayList list = (ArrayList) map.get(key);
				sb.append("<" + key + ">");
				for (int i = 0; i < list.size(); i++) {
					HashMap hm = (HashMap) list.get(i);
					mapToXMLTest2(hm, sb);
				}
				sb.append("</" + key + ">");

			} else {
				if (value instanceof HashMap) {
					sb.append("<" + key + ">");
					mapToXMLTest2((HashMap) value, sb);
					sb.append("</" + key + ">");
				} else {
					sb.append("<" + key + ">" + value + "</" + key + ">");
				}

			}

		}
	}

	/**
	 * xml转map 不带属性
	 * 
	 * @param xmlStr
	 * @param needRootKey
	 *            是否需要在返回的map里加根节点键
	 * @return
	 * @throws DocumentException
	 */
	@SuppressWarnings({"rawtypes","unchecked"})
	public static Map xmlToMap(String xmlStr, boolean needRootKey) throws DocumentException {
		Document doc = DocumentHelper.parseText(xmlStr);
		Element root = doc.getRootElement();
		Map<String, Object> map = (Map<String, Object>) xmlToMap(root);
		if (root.elements().size() == 0 && root.attributes().size() == 0) {
			return map;
		}
		if (needRootKey) {
			// 在返回的map里加根节点键（如果需要）
			Map<String, Object> rootMap = new HashMap<String, Object>();
			rootMap.put(root.getName(), map);
			return rootMap;
		}
		return map;
	}

	/**
	 * xml转map 带属性
	 * 
	 * @param xmlStr
	 * @param needRootKey
	 *            是否需要在返回的map里加根节点键
	 * @return
	 * @throws DocumentException
	 */
	@SuppressWarnings({"rawtypes","unchecked"})
	public static Map xmlToMapWithAttr(String xmlStr, boolean needRootKey) throws DocumentException {
		Document doc = DocumentHelper.parseText(xmlStr);
		Element root = doc.getRootElement();
		Map<String, Object> map = (Map<String, Object>) xmlToMapWithAttr(root);
		if (root.elements().size() == 0 && root.attributes().size() == 0) {
			return map; // 根节点只有一个文本内容
		}
		if (needRootKey) {
			// 在返回的map里加根节点键（如果需要）
			Map<String, Object> rootMap = new HashMap<String, Object>();
			rootMap.put(root.getName(), map);
			return rootMap;
		}
		return map;
	}

	/**
	 * xml转map 不带属性
	 * 
	 * @param element
	 * @return
	 */
	@SuppressWarnings({"unchecked"})
	private static Object xmlToMap(Element element) {
		// System.out.println(element.getName());
		Map<String, Object> map = new LinkedHashMap<String, Object>();
		List<Element> elements = element.elements();
		if (elements.size() == 0) {
			map.put(element.getName(), element.getText());
			if (!element.isRootElement()) {
				return element.getText();
			}
		} else if (elements.size() == 1) {
			map.put(elements.get(0).getName(), xmlToMap(elements.get(0)));
		} else if (elements.size() > 1) {
			// 多个子节点的话就得考虑list的情况了，比如多个子节点有节点名称相同的
			// 构造一个map用来去重
			Map<String, Element> tempMap = new LinkedHashMap<String, Element>();
			for (Element ele : elements) {
				tempMap.put(ele.getName(), ele);
			}
			Set<String> keySet = tempMap.keySet();
			for (String string : keySet) {
				Namespace namespace = tempMap.get(string).getNamespace();
				List<Element> elements2 = element.elements(new QName(string, namespace));
				// 如果同名的数目大于1则表示要构建list
				if (elements2.size() > 1) {
					List<Object> list = new ArrayList<Object>();
					for (Element ele : elements2) {
						list.add(xmlToMap(ele));
					}
					map.put(string, list);
				} else {
					// 同名的数量不大于1则直接递归去
					map.put(string, xmlToMap(elements2.get(0)));
				}
			}
		}

		return map;
	}

	/**
	 * xml转map 带属性
	 * 
	 * @param element
	 * @return
	 */
	@SuppressWarnings({"unchecked"})
	private static Object xmlToMapWithAttr(Element element) {
		// System.out.println(element.getName());
		Map<String, Object> map = new LinkedHashMap<String, Object>();
		List<Element> elements = element.elements();

		List<Attribute> listAttr = element.attributes(); // 当前节点的所有属性的list
		boolean hasAttributes = false;
		for (Attribute attr : listAttr) {
			hasAttributes = true;
			map.put("@" + attr.getName(), attr.getValue());
		}

		if (elements.size() == 0) {
			// map.put(element.getName(), element.getText());
			if (hasAttributes) {
				map.put("#text", element.getText());
			} else {
				map.put(element.getName(), element.getText());
			}

			if (!element.isRootElement()) {
				// return element.getText();
				if (!hasAttributes) {
					return element.getText();
				}
			}
		} else if (elements.size() == 1) {
			map.put(elements.get(0).getName(), xmlToMapWithAttr(elements.get(0)));
		} else if (elements.size() > 1) {
			// 多个子节点的话就得考虑list的情况了，比如多个子节点有节点名称相同的
			// 构造一个map用来去重
			Map<String, Element> tempMap = new LinkedHashMap<String, Element>();
			for (Element ele : elements) {
				tempMap.put(ele.getName(), ele);
			}
			Set<String> keySet = tempMap.keySet();
			for (String string : keySet) {
				Namespace namespace = tempMap.get(string).getNamespace();
				List<Element> elements2 = element.elements(new QName(string, namespace));
				// 如果同名的数目大于1则表示要构建list
				if (elements2.size() > 1) {
					List<Object> list = new ArrayList<Object>();
					for (Element ele : elements2) {
						list.add(xmlToMapWithAttr(ele));
					}
					map.put(string, list);
				} else {
					// 同名的数量不大于1则直接递归去
					map.put(string, xmlToMapWithAttr(elements2.get(0)));
				}
			}
		}

		return map;
	}

	/**
	 * map转xml报文
	 * 
	 * @param map
	 *            需要转换的数据
	 * @param encoding
	 *            转换数据的字符集
	 * @param root
	 *            根节点
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public static byte[] mapToXML(Map map, String encoding, List<String> rootList) {
		StringBuffer sb = new StringBuffer();
		sb.append("<?xml version=\"1.0\" encoding=\"" + encoding + "\"?>");
		for(String preRoot:rootList){
			sb.append("<" + preRoot + ">");
		}
		mapToXMLTest2(map, sb);
		Collections.reverse(rootList);
		for(String preRoot:rootList){
			sb.append("</" + preRoot + ">");
		}
		//System.out.println(sb.toString());
		try {
			System.out.println(sb.toString().getBytes(encoding));
			return sb.toString().getBytes(encoding);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return null;
	}

	// public static void main(String[] args) throws DocumentException,
	// IOException {
	// String xml = "<ap> <head> <tr_code>330003</tr_code>
	// <corp_no>8000500436</corp_no> <user_no>22222</user_no>
	// <req_no>123456789001</req_no> <tr_acdt>20160510</tr_acdt>
	// <tr_time>151238</tr_time> <atom_tr_count>1</atom_tr_count>
	// <channel>0</channel> <reserved /> </head> <body>
	// <cert_no>TEST01234</cert_no> <pay_acno>310066865018010123060</pay_acno>
	// <type>S</type> <sum>1</sum> <sum_amt>0.01</sum_amt>
	// <pay_month>201605</pay_month> <summary>测试0.01</summary>
	// <busi_no>3100012379</busi_no>
	// <selsec_flg>0</selsec_flg><tran><rcd><card_no>00000001</card_no><acname>测试账号</acname><card_flag>0</card_flag><amt>21.01</amt><busino>111111111</busino></rcd><rcd><card_no>00000001</card_no><acname>测试账号</acname><card_flag>0</card_flag><amt>21.01</amt><busino>111111111</busino></rcd></tran>
	// </body></ap>";
	// System.out.println(xmlToMap(xml,false));
	// }
	public static void main(String[] args) {
		Map map = new HashMap<String,String>();
		map.put("serverFileName", "temp.rar");
		map.put("clientFileName", "D:\\w.txt");
		map.put("tradeCode","1");
		List rootList =  new ArrayList<String>();
		rootList.add("xmlMobile");
		rootList.add("Body");
		rootList.add("ReqDownLoadFile");
		rootList.add("SvcBody");
		mapToXML(map, "GB2312", rootList);
	}

}

